#pragma once

#include "common/logger.h"

#include <pthread.h>
#include <semaphore.h>

using namespace bustub;

//信号量类
class Sem {
 private:
  sem_t m_sem;

 public:
  //默认信号量初始为0
  Sem() {
    if (sem_init(&m_sem, 0, 0) != 0) {
      LOG_ERROR("sem_init erorr");
    }
  }

  //信号量初始为num
  Sem(int num) {
    if (sem_init(&m_sem, 0, num) != 0) {
      LOG_ERROR("sem_init error");
    }
  }

  ~Sem() { sem_destroy(&m_sem); }

  //阻塞在信号量，直到其大于0, --m_sem
  void wait() {
    if (sem_wait(&m_sem) != 0) {
      LOG_ERROR("sem_wait error");
    }
  }

  //唤醒阻塞， ++m_sem
  void post() {
    if (sem_post(&m_sem) != 0) {
      LOG_ERROR("sem_post error");
    }
  }
};

//互斥量
class Lock {
 private:
  pthread_mutex_t m_mutex;

 public:
  Lock() {
    if (pthread_mutex_init(&m_mutex, NULL) != 0) {
      LOG_ERROR("pthread_mutex_init error");
    }
  }

  ~Lock() { pthread_mutex_destroy(&m_mutex); }

  //枷锁
  void lock() {
    if (pthread_mutex_lock(&m_mutex) != 0) {
      LOG_ERROR("pthread_mutex_lock error");
    }
  }

  //解锁
  void unlock() {
    if (pthread_mutex_unlock(&m_mutex) != 0) {
      LOG_ERROR("Pthread_mutex_unlock error");
    }
  }

  //获取锁变量
  pthread_mutex_t *get() { return &m_mutex; }
};

class Cond {
 private:
  pthread_cond_t m_cond;

 public:
  Cond() {
    if (pthread_cond_init(&m_cond, NULL) != 0) {
      LOG_ERROR("pthread_cond_init error");
    }
  }

  ~Cond() { pthread_cond_destroy(&m_cond); }

  //等待条件变量满足：1.先对mutex解锁，2.阻塞等待 3.返回前对mutex枷锁
  void wait(pthread_mutex_t *mutex) {
    if (pthread_cond_wait(&m_cond, mutex) != 0) {
      LOG_ERROR("pthread_cond_wait error");
    }
  }

  //限时等待，用法：
  // time_t = time(NULL); 获取当前时间
  // struct timespec t;
  // t.tv_sec = cur + 1;   定时1s
  void timeWait(pthread_mutex_t *mutex, struct timespec t) {
    if (pthread_cond_timedwait(&m_cond, mutex, &t) != 0) {
      LOG_ERROR("pthread_cond_timedwait error");
    }
  }

  //唤醒至少1个线程
  void signal() { pthread_cond_signal(&m_cond); }

  //唤醒所有阻塞在cond的线程
  void broadcast() { pthread_cond_broadcast(&m_cond); }
};
